//--------------------------------------------------------------------------------------//
//                                                                                      //
//    __  __  __    __    __  ___   __   ___  __    ___    __  __  __  ___  ___  __     //
//   / _)/  \(  )  (  )  (  )(   \ (  ) (  ,)(  )  (  _)  (  \/  )/  \(   \(  _)(  )    //
//  ( (_( () ))(__  )(__  )(  ) ) )/__\  ) ,\ )(__  ) _)   )    (( () )) ) )) _) )(__   //
//   \__)\__/(____)(____)(__)(___/(_)(_)(___/(____)(___)  (_/\/\_)\__/(___/(___)(____)  //
//                                                                                      //
//                                                                                      //
//       Copyright by Theodor Mader, 2009                                               //
//			www.theomader.com/public/Projects.html                                      //
//--------------------------------------------------------------------------------------//

#include <iostream>

#include <cmath>
#include <fstream>
#include <list>
#include <iomanip>
#include <algorithm>
#include <set>

#include "objparser/ObjParser.h"
#include "Geometry.h"
#include "BspTree.h"

using namespace Geometry;
using namespace std;

void printUsage( const char* progName ) 
{
	cout << progName << " generates a BSP from a given OBJ file" << endl;
	cout << "Usage: " << progName << " <Obj File Name> <Number of Vertices per BSP node>" << endl;
}


int main( int argc, char** argv ) 
{
	if( argc != 3 ) 
	{
		printUsage( argv[0] );
		return EXIT_FAILURE;
	}

	string objFile( argv[1] );
	unsigned int numVerticesPerLeaf = atoi( argv[2] );
	cout << "Reading geometry data from " << objFile << endl;

	// parse given obj file
	vector<Vertex> vertices;
	vector<Vertex> normals;
	vector<Face> faces;

	ObjParser parser( objFile );
	bool bParseSuccess = parser.Parse( vertices, normals, faces );
	if( !bParseSuccess ) 
	{
		cout << "\tFailed to open and parse " << objFile << ". Aborting..." << endl;
		return EXIT_FAILURE;
	}

		// create bsp tree
	int numLeafs = static_cast<int>( ceil( static_cast<double>( vertices.size() ) / numVerticesPerLeaf ) );
	int numNodes = 2 * numLeafs - 1;
	int depth = static_cast<int>( ceil( log( static_cast<double>( numLeafs ) ) / log( 2.0 ) + 1 ) );

	// filter duplicate vertices
	set<Vertex> uniqueVertices( vertices.begin(), vertices.end() );
	vertices.assign( uniqueVertices.begin(), uniqueVertices.end() );

	cout << "Start creating BSP tree with " << numVerticesPerLeaf << " vertices per leaf, expecting" << endl;
	cout << "\tNumber of leafs: " << numLeafs  << endl;
	cout << "\tNumber of nodes: " << numNodes << endl;
	cout << "\tTree height: " << depth << endl << endl;

	DWORD beg = GetTickCount();

	BspTree tree( vertices, numVerticesPerLeaf );
	tree.BuildMT( 4 );

	DWORD end = GetTickCount();
	cout << "\tDone in " << (DWORD)(end-beg) <<" ms" << endl;
	
	// write bsp tree to <inputFile>.bsp
	string bspTree( objFile );
	bspTree.replace( objFile.size()-4, 4, ".bsp" );

	cout << "Saving Tree to " << bspTree << endl;
	tree.SaveToFile( bspTree );
	ofstream outFile( bspTree.c_str(), ios_base::binary | std::ios_base::app );

	// write vertices
	int numVertices = static_cast<int>( vertices.size() );
	outFile.write( (char*)&numVertices, sizeof( unsigned int ) );
	for( int i=0; i<numVertices; i++ ) {
		outFile.write( (char*)&vertices[i].x, sizeof( float ) );
		outFile.write( (char*)&vertices[i].y, sizeof( float ) );
		outFile.write( (char*)&vertices[i].z, sizeof( float ) );
	}

	// write normals
	int numNormals = static_cast<int>( normals.size() );
	outFile.write( (char*)&numNormals, sizeof( unsigned int ) );
	for( int i=0; i<numNormals; i++ ) {
		outFile.write( (char*)&normals[i].x, sizeof( float ) );
		outFile.write( (char*)&normals[i].y, sizeof( float ) );
		outFile.write( (char*)&normals[i].z, sizeof( float ) );
	}

	// write faces
	int numFaces = static_cast<int>( faces.size() );
	outFile.write( (char*)&numFaces, sizeof( unsigned int ) );
	for( int i=0; i<numFaces; i++ ) {
		outFile.write( (char*)&faces[i].v1, sizeof( unsigned int ) );
		outFile.write( (char*)&faces[i].n1, sizeof( unsigned int ) );
		
		outFile.write( (char*)&faces[i].v2, sizeof( unsigned int ) );
		outFile.write( (char*)&faces[i].n2, sizeof( unsigned int ) );

		outFile.write( (char*)&faces[i].v3, sizeof( unsigned int ) );
		outFile.write( (char*)&faces[i].n3, sizeof( unsigned int ) );

	}
	
	// do some cleanup
	outFile.close();
	cout << "\tDone" << endl << endl;

	system( "pause" );
	return 0;
}

